///@file Complex.cpp
///@brief Implementation of the class representing a complex number
///@author Arnaud Duval
///@version 0.0
///@date 2009/11/03

#include "Complex.h"
#include <cmath>

///@brief Default constructor
Complex::Complex()
{
	real = 0.;
	imaginary = 0.;
}

///@brief Constructor with argument
///@param Dr given real part
///@param Di given imaginary part
Complex::Complex(double Dr, double Di)
{
	real = Dr;
	imaginary = Di;
}

///@brief Copy constructor
///@param c Complex number to copy
Complex::Complex(const Complex &c)
{
	real = c.real;
	imaginary = c.imaginary;
}

///@brief Copy constructor for temporary object
///@param c temporary complex number to copy
Complex::Complex(Complex* c)
{
	real = (*c).real;
	imaginary = (*c).imaginary;
}

///@brief Destructor
Complex::~Complex()
{

}

///@brief Overload of = operator
///@param c right hand operand
Complex& Complex::operator=(const Complex &c)
{
	real = c.real;
	imaginary = c.imaginary;
	return (*this);
}

///@brief Overload of = operator for temporary object
///@param c right hand operand
Complex& Complex::operator=(Complex* c)
{
	real = (*c).real;
	imaginary = (*c).imaginary;
	return (*this);
}

///@brief Overload of [] operator, access to real or imaginary part
///@param idx Index of part to return : 1 for real and 2 for imaginay
double& Complex::operator[](unsigned int idx)
{
	assert((idx == 1)||(idx == 2));
	if(idx == 1)
		return real;
	else
		return imaginary;
}

///@brief Overload of += operator
///@param c Complex number to add to cuurent one
void Complex::operator += (const Complex& c)
{
	real += c.real;
	imaginary += c.imaginary;

}

///@brief Overload of -= operator
///@param c Complex number to substract to current one
void Complex::operator -= (const Complex& c)
{
	real -= c.real;
	imaginary -= c.imaginary;
}

///@brief Compute argument
double Complex::Argument()
{
	if((imaginary == 0.)&&(real < 0.))
		return 4.*atan(1.);
	return 2.*atan(imaginary / (real + Norm()));
}

///@brief Compute norm
double Complex::Norm()
{
	return sqrt(pow(real, 2.) + pow(imaginary, 2.));
}

///@brief Compute conjugate complex number
Complex Complex::Conjugate()
{
	Complex res(real, -imaginary);
	return res;
}	


///@brief Overload of + operator
///@param c1 left hand operand
///@param c2 right hand operand
Complex operator + (const Complex& c1, const Complex& c2)
{
	Complex res;
	res.real = c1.real + c2.real;
	res.imaginary = c1.imaginary + c2.imaginary;
	return res;
}

///@brief Overload of - operator
///@param c1 left hand operand
///@param c2 right hand operand
Complex operator - (const Complex &c1, const Complex& c2)
{
	Complex res;
	res.real = c1.real - c2.real;
	res.imaginary = c1.imaginary - c2.imaginary;
	return res;
}

///@brief Overload of * operator : product complex-real
///@param c left hand operand
///@param r right hand operand
Complex operator * (const Complex& c, const double& r)
{
	Complex res;
	res.real = c.real*r;
	res.imaginary = c.imaginary*r;
	return res;
}

///@brief Overload of * operator : product real-complex
///@param r left hand operand
///@param c right hand operand
Complex operator * (const double& r, const Complex& c)
{
	Complex res;
	res.real = c.real*r;
	res.imaginary = c.imaginary*r;
	return res;
}

///@brief Overload of * operator : product complex-complex
///@param c1 left hand operand
///@param c2 right hand operand
Complex operator * (const Complex& c1, const Complex& c2)
{
	Complex res;
	res.real = c1.real*c2.real - c1.imaginary*c2.imaginary;
	res.imaginary = c1.imaginary*c2.real + c2.imaginary*c1.real;
	return res;
}

///@brief Overload of / operator : division of a complex by a real
///@param c left hand operand
///@param r right hand operand
Complex operator / (const Complex& c, const double& r)
{
	assert(r != 0.);
	Complex res;
	res.real = c.real / r;
	res.imaginary = c.imaginary / r;
	return res;
}

///@brief Overload of / operator : division of a real by a complex
///@param r left hand operand
///@param c right hand operand
Complex operator / (const double& r, const Complex& c)
{
	assert((c.real != 0.)||(c.imaginary != 0.));
	Complex res;
	res.real = r*c.real / (pow(c.real, 2.) + pow(c.imaginary, 2.));
	res.real = -r*c.imaginary / (pow(c.real, 2.) + pow(c.imaginary, 2.));
	return res;
}

///@brief Overload of / operator : division of a complex by a complex
///@param c1 left hand operand
///@param c2 right hand operand
Complex operator / (const Complex& c1, const Complex& c2)
{
	assert((c2.real != 0.)||(c2.imaginary != 0.));
	Complex res;
	res.real = (c1.real*c2.real + c1.imaginary*c2.imaginary)/(pow(c2.real, 2.) + pow(c2.imaginary, 2.));
	res.real = (c1.imaginary*c2.real - c1.real*c2.imaginary)/(pow(c2.real, 2.) + pow(c2.imaginary, 2.));
	return res;
}


///@brief Overload of << operator
///@param s out stream
///@param c Complex object to put in the out stream
std::ostream& operator<<(std::ostream & s, const Complex& c)
{
	s << c.real;
	if(c.imaginary >= 0.)
		s << "+";
	s << c.imaginary << "*i";
	return s;
}